package net.oktaeder.office.utils.database;

import net.oktaeder.office.ConfigurationHelper;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.sql.Connection;
import java.sql.DriverManager;

/**
 * Class used to abstract database connections.
 * 
 * @author tuukka
 *
 */
public class Database {

	private static Log log = LogFactory.getLog(Database.class);
	private static Database instance;
	
	private String driver;
	private String protocol;
	private String location;
	
	private Database() {
		log.info("Starting the database");
		//TODO: implement
	}
	
	/**
	 * Get the instance of Database that can be used to manipulate the database
	 * connection. This class has been implemented as a singleton, meaning that
	 * there will be only zero or one instance at any given time.
	 * 
	 * @return configured instance of the Database class
	 * @throws Exception when something fails
	 */
	public static synchronized Database getInstance() throws Exception {
		try {
			if (instance == null) {
				instance = new Database();
				instance.initialize();
			}
			return instance;			
		} catch (Exception ex) {
			log.error("Failed to get instance of Database", ex);
			throw new Exception("Failed to get instance of Database", ex);
		}
	}
	
	/**
	 * Initialize this instance of the database. Reads information from the
	 * configuration
	 * 
	 * @throws Exception when something fails
	 */
	private void initialize() throws Exception {
		
		Configuration config;
		try {
			config = ConfigurationHelper.getConfiguration();
			driver = config.getString("system.database.driver[@class]");
			protocol = config.getString("system.database.protocol[@value]");
			location = config.getString("system.database.file[@name]");
			//start up derby (does this work with other databases too?)
			Class.forName(driver).newInstance();
		} catch (Exception ex) {
			log.error("Failed to initialize database", ex);
			throw new Exception("Failed to initialize database", ex);
		}
	}
	
	/**
	 * Get a connection to the database
	 * 
	 * @return Connection to the database
	 * @throws Exception thrown when something fails
	 */
	public Connection getConnection() throws Exception {
		//TODO: implement properly
		try {
			return DriverManager.getConnection(protocol + location);
		} catch (Exception ex) {
			log.error("Failed to get database connection", ex);
			throw new Exception("Failed to get database connection", ex);
		}
	}
	
	/**
	 * Shutdown the database in a clean way.
	 * 
	 * @throws Exception thrown when something fails
	 */
	public void shutdown() throws Exception {
		try {
			DriverManager.getConnection("jdbc:derby:;shutdown=true");
		} catch (Exception ex) {
			log.error("Failed to shutdown database", ex);
			throw new Exception("Failed to shutdown database", ex);
		}
	}
}